`include "PRV564Config.v"
`include "PRV564Define.v"
/*****************************************************************************************
 *    author  : Jack's Team
 *    engineer: Jack PAN
 *    e-mail  : 
 *    date    : 20210828
 *    desc    : PRV564 SFR (include CLINT and other SFR)
 *    version : 0000 (Original)
 
**********************************************************************************************/
module SFR(
//----------------SFR Slave interface-------------------
    //       Global signal input
    input  wire             CLKi,
    input  wire             ARSTi,
    //        access from master
    input  wire [`XLEN-1:0] SFRi_ADDR,
    input  wire [`XLEN-1:0] SFRi_DATA,
    input  wire             SFRi_CS,
    input  wire             SFRi_WR,
    output  reg [`XLEN-1:0] SFRo_DATA,
    //       
    output wire             CLINT_MTI,
    output wire             CLINT_MSI,
    output wire [`XLEN-1:0] CLINT_MTIME
);
    reg [`XLEN-1:0] mtime,  mtimecmp,   msoftinterrupt;

always@(posedge CLKi or posedge ARSTi)begin
    if(ARSTi)begin
        mtime           <= 64'h0;
        mtimecmp        <= 64'h0;
        msoftinterrupt  <= 64'h0;
    end
    else if(SFRi_CS & SFRi_WR)begin
        case(SFRi_ADDR)
            `SFR_MTIME_ADDR    :begin 
                                    mtime          <= SFRi_DATA;
                                    $display("SFR: mtime is writen, data=%h",SFRi_DATA);
                                end
            `SFR_MTIMECMP_ADDR :begin
                                    mtimecmp       <= SFRi_DATA;
                                    $display("SFR: mtimecmp is writen, data=%h",SFRi_DATA);
                                end
            `SFR_MSOFTINT_ADDR :begin
                                    msoftinterrupt <= SFRi_DATA;
                                    $display("SFR: msoft is writen, data=%h",SFRi_DATA);
                                end
            default:
            begin
                mtimecmp<=mtimecmp;
                msoftinterrupt <=msoftinterrupt ;
                mtime <= mtime + 64'd1;
            end
        endcase
    end
    else begin
        mtime <= mtime + 64'd1;
    end
end
always@(*)begin
    case(SFRi_ADDR)
        `SFR_MTIME_ADDR     : SFRo_DATA = mtime;
        `SFR_MTIMECMP_ADDR  : SFRo_DATA = mtimecmp;
        `SFR_MSOFTINT_ADDR  : SFRo_DATA = msoftinterrupt;
        default : SFRo_DATA = 64'hx;
    endcase
end
assign CLINT_MTI    = (mtime > mtimecmp);
assign CLINT_MSI    = msoftinterrupt[0];
assign CLINT_MTIME  = mtime;

endmodule